﻿/*
* Copyright (c) 2010-2012 Tesla Engine Group
* 
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
* 
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
* 
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

using System;
using System.IO;

namespace Tesla.Content {
    /// <summary>
    /// Class that is responsible for serializing a runtime object and saving it.
    /// </summary>
    public abstract class ResourceExporter {
        private String _extension;
        private Type _targetType;

        /// <summary>
        /// Gets the exporter's file extension.
        /// </summary>
        public String Extension {
            get {
                return _extension;
            }
        }

        /// <summary>
        /// Gets the target type of resource to export.
        /// </summary>
        public Type TargetType {
            get {
                return _targetType;
            }
        }

        /// <summary>
        /// Creates a new resource exporter.
        /// </summary>
        /// <param name="targetType">Target type of resource</param>
        /// <param name="extension">Extension of format the resource will be serialized to</param>
        protected ResourceExporter(Type targetType, String extension) {
            _extension = extension;
            _targetType = targetType;
        }

        /// <summary>
        /// Serializes an object to the stream.
        /// </summary>
        /// <param name="value">Object to serialize</param>
        /// <param name="output">Stream to serialize the object into</param>
        public abstract void Save(Object value, Stream output);

        /// <summary>
        /// Serializes an object and saves it to a file.
        /// </summary>
        /// <param name="value">Object to serialize</param>
        /// <param name="filePath">Full path to the file</param>
        public abstract void Save(Object value, String filePath);
    }

    /// <summary>
    /// Strongly typed resource exporter. Subclass this to add new exporters for different object types.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public abstract class ResourceExporter<T> : ResourceExporter {

        /// <summary>
        /// Creates a new resource exporter.
        /// </summary>
        /// <param name="extension">Extension of format the resource will be serialized to</param>
        protected ResourceExporter(String extension) : base(typeof(T), extension) {}

        /// <summary>
        /// Serializes an object to the stream.
        /// </summary>
        /// <param name="value">Object to serialize</param>
        /// <param name="output">Stream to serialize the object into</param>
        public override void Save(Object value, Stream output) {
            if(value == null) {
                throw new ArgumentNullException("Object to save cannot be null.");
            }

            if(output == null) {
                throw new ArgumentNullException("Stream to write object to cannot be null.");
            }

            Type type = value.GetType();
            if(!TargetType.IsAssignableFrom(type)) {
                throw new InvalidCastException(String.Format("Invalid type, cannot save specified type: {0}, expected type: {1}.", type.FullName, TargetType.FullName));
            }

            Save((T) value, output);
        }

        /// <summary>
        /// Serializes an object to the stream.
        /// </summary>
        /// <param name="value">Object to serialize</param>
        /// <param name="output">Stream to serialize the object into</param>
        public abstract void Save(T value, Stream output);

        /// <summary>
        /// Serializes an object and saves it to a file.
        /// </summary>
        /// <param name="value">Object to serialize</param>
        /// <param name="filePath">Full path to the file</param>
        public override void Save(Object value, String filePath) {
            if(value == null) {
                throw new ArgumentNullException("Object to save cannot be null.");
            }

            if(filePath == null) {
                throw new ArgumentNullException("File path cannot be null.");
            }

            Type type = value.GetType();
            if(!TargetType.IsAssignableFrom(type)) {
                throw new InvalidCastException(String.Format("Invalid type, cannot save specified type: {0}, expected type: {1}.", type.FullName, TargetType.FullName));
            }

            Save((T) value, filePath);
        }

        /// <summary>
        /// Serializes an object and saves it to a file.
        /// </summary>
        /// <param name="value">Object to serialize</param>
        /// <param name="filePath">Full path to the file</param>
        public abstract void Save(T value, String filePath);
    }
}
